#pragma once
#include "Utility.h"

#define __EPSILON__			1e-6f

inline float round(float x)
{
	float r = floor(x);
	return (x - r >= 0.5f ? r + 1 : r);
}


class IDataProvider
{
public:
	virtual UINT GetCount() = 0;
	virtual float GetDistance(UINT i, void* pos) = 0;
	virtual float GetDistance(UINT i, UINT j) = 0;
	virtual float GetData(UINT i) = 0;
};

class CZProvider : public IDataProvider
{
public:
	CZProvider(const CArray2D<glm::vec3>& _cDrillData, UINT _uiStratum)
		: cDrillData(_cDrillData)
		, uiStratum(_uiStratum)
	{
	}

	virtual UINT GetCount()
	{
		return cDrillData.GetHeight();
	}

	virtual float GetDistance(UINT i, void* pos)
	{
		return glm::length(glm::vec2(
			cDrillData[i][uiStratum].x - ((glm::vec2*)pos)->x, 
			cDrillData[i][uiStratum].y - ((glm::vec2*)pos)->y));
	}

	virtual float GetDistance(UINT i, UINT j)
	{
		return glm::length(glm::vec2(
			cDrillData[i][uiStratum].x - cDrillData[j][uiStratum].x, 
			cDrillData[i][uiStratum].y - cDrillData[j][uiStratum].y));
	}

	virtual float GetData(UINT i)
	{
		return cDrillData[i][uiStratum].z;
	}

	const CArray2D<glm::vec3>& cDrillData;
	UINT uiStratum;
};

class CPropertyProvider : public IDataProvider
{
public:
	CPropertyProvider(glm::vec4* _pInputData, UINT _uiInputCount)
		: pInputData(_pInputData)
		, uiInputCount(_uiInputCount)
	{
	}

	virtual UINT GetCount()
	{
		return uiInputCount;
	}

	virtual float GetDistance(UINT i, void* pos)
	{
		return glm::length(glm::vec3(
			pInputData[i].x - ((glm::vec3*)pos)->x, 
			pInputData[i].y - ((glm::vec3*)pos)->y, 
			pInputData[i].z - ((glm::vec3*)pos)->z));
	}

	virtual float GetDistance(UINT i, UINT j)
	{
		return glm::length(glm::vec3(
			pInputData[i].x - pInputData[j].x, 
			pInputData[i].y - pInputData[j].y, 
			pInputData[i].z - pInputData[j].z));
	}

	virtual float GetData(UINT i)
	{
		return pInputData[i].w;
	}

	glm::vec4* pInputData;
	UINT uiInputCount;
};
